package lei.main;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableField.MetaInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.type.ITypeConvertHandler;
import com.baomidou.mybatisplus.generator.type.TypeRegistry;
import org.apache.commons.lang3.StringUtils;

import java.sql.Types;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * MybatisPlus 代码生成器，详细配置以及项目初始化基本类创建代码请看 README.md
 *
 * @author:张三石
 * @since:2023年4月3日
 */
public class CodeGenerator {

    // 数据库相关参数
    private static final String url = "jdbc:mysql://localhost:3306/dby";
    // private static String driverName = "com.mysql.cj.jdbc.Driver";
    private static final String username = "root";
    private static final String password = "root";

    // 作者名
    private static final String author = "三石";

    // 代码生成目录
    private static final String outputDir = "F:/code-generate";

    // 包名设置
    private static final String parent = "video"; // 父包名。如果为空，将下面子包名必须写全部， 否则就只需写子包名
    private static String moduleName = ""; // 父包模块名
    private static final String entity = "entity"; // Entity包名
    private static final String vo = entity + ".vo"; // VO包名
    private static final String dto = entity + ".dto"; // DTO包名
    private static final String service = "service"; // Service包名
    private static final String serviceImpl = "service.impl"; // Service Impl包名
    private static final String mapper = "mapper"; // Mapper包名
    private static final String xml = "mapper.xml"; // Mapper XML包名
    private static final String controller = "controller"; // Controller包名

    // 字段名设置依次为：创建人ID、创建时间、修改人ID、修改时间，逻辑删除
    private static final String createBy = "create_by";
    private static final String createTime = "create_time";
    private static final String updateBy = "update_by";
    private static final String updateTime = "update_time";
    private static final String isDeleted = "is_deleted";

    // 类名后缀
    private static final String detailVOSuffix = "DetailVO";
    private static final String listVOSuffix = "ListVO";
    private static final String dtoSuffix = "DTO";
    /**
     * 增加DefaultQuery对double类型的处理
     */
    private static final ITypeConvertHandler typeConvertHandler = new ITypeConvertHandler() {

        @Override
        public IColumnType convert(GlobalConfig globalConfig, TypeRegistry typeRegistry, MetaInfo metaInfo) {

            int typeCode = metaInfo.getJdbcType().TYPE_CODE;

            if (Types.DOUBLE == typeCode) {
                return DbColumnType.DOUBLE;
            }
            return typeRegistry.getColumnType(metaInfo);
        }
    };

    public static void main(String[] args) {

        FastAutoGenerator
                // 数据库配置
                .create(DataSourceConfig())
                // 全局配置
                .globalConfig(globalConfig())
                // 包配置
                .packageConfig(packageConfig())
                // 模板引擎配置
                .templateEngine(templateEngine())
                // 模板配置
                .templateConfig(templateConfig())
                // 注入配置(InjectionConfig)
                .injectionConfig(injectionConfig())
                // 策略配置
                .strategyConfig(strategyConfig())

                .execute();
    }

    /**
     * 策略配置(StrategyConfig)
     */
    private static BiConsumer<Function<String, String>, StrategyConfig.Builder> strategyConfig() {
        return (scanner, builder) -> {
            String tables = scanner.apply("请输入表名，多个英文逗号分隔？所有输入:all");
            builder//
                    .addInclude("all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(",")))//
                    /*
                     *  entity
                     */.entityBuilder()//
                    // .superClass(parent + "." + entity + ".BaseEntity")
                    .idType(IdType.AUTO)//
                    .enableLombok()//
                    .enableChainModel()//
                    .logicDeleteColumnName(isDeleted)//

                    .addTableFills(//
                            new Column(createBy, FieldFill.INSERT), //
                            new Column(createTime, FieldFill.INSERT), //
                            new Column(updateBy, FieldFill.UPDATE), //
                            new Column(updateTime, FieldFill.UPDATE)//
                    )//
                    /*
                     *  controller
                     */.controllerBuilder()//
                    .enableRestStyle()//
                    .enableHyphenStyle()//
                    /*
                     *  service
                     */.serviceBuilder().formatServiceFileName("%sService");
        };
    }

    /**
     * 注入配置(InjectionConfig)
     */
    private static BiConsumer<Function<String, String>, InjectionConfig.Builder> injectionConfig() {
        DefaultIdentifierGenerator dig = new DefaultIdentifierGenerator();
        // 存放实体类、DTO、VO的serialVersionUID
        Map<String, Object> svmap = new HashMap<>();
        svmap.put("entityUID", dig.nextId(null));
        svmap.put("dtoUID", dig.nextId(null));
        svmap.put("listUID", dig.nextId(null));
        svmap.put("detailUID", dig.nextId(null));

        List<CustomFile> customFiles = new ArrayList<>();
        customFiles.add(new CustomFile.Builder().fileName(dtoSuffix + ".java").templatePath("/templates/entity/dto/dto.java.vm").packageName(dto).build());
        customFiles.add(new CustomFile.Builder().fileName(detailVOSuffix + ".java").templatePath("/templates/entity/vo/detailVO.java.vm").packageName(vo).build());
        customFiles.add(new CustomFile.Builder().fileName(listVOSuffix + ".java").templatePath("/templates/entity/vo/listVO.java.vm").packageName(vo).build());

        return (scanner, builder) -> builder//
                .customMap(svmap)//
                .customFile(customFiles)//
                .beforeOutputFile((tableInfo, objectMap) -> {

                    /*
                     * 创建自定包名map并添加vo和dto的包名
                     */
                    String voPackageName = "";
                    String dtoPackageName = "";

                    if (StringUtils.isNotBlank(parent)) {
                        if (StringUtils.isNotBlank(moduleName)) {
                            voPackageName = parent + StringPool.DOT + moduleName + StringPool.DOT + vo;
                            dtoPackageName = parent + StringPool.DOT + moduleName + StringPool.DOT + dto;
                        } else {
                            voPackageName = parent + StringPool.DOT + vo;
                            dtoPackageName = parent + StringPool.DOT + dto;
                        }
                    } else {
                        if (StringUtils.isNotBlank(moduleName)) {
                            voPackageName = moduleName + StringPool.DOT + vo;
                            dtoPackageName = moduleName + StringPool.DOT + dto;
                        } else {
                            voPackageName = vo;
                            dtoPackageName = dto;
                        }
                    }

                    Map<String, String> selfPackage = new HashMap<>();
                    selfPackage.put("VO", voPackageName);
                    selfPackage.put("DTO", dtoPackageName);
                    // 添加到对象map
                    objectMap.put("selfPackage", selfPackage);

                    /*
                     * 创建VO和DTO类名后缀
                     */
                    Map<String, String> selfClassNameSuffix = new HashMap<>();
                    selfClassNameSuffix.put("DetailVO", detailVOSuffix);
                    selfClassNameSuffix.put("ListVO", listVOSuffix);
                    selfClassNameSuffix.put("DTO", dtoSuffix);
                    // 添加到对象map
                    objectMap.put("selfClassNameSuffix", selfClassNameSuffix);

                    // 增加逻辑删除字段@JsonIgnore导包信息
                    tableInfo.getFields().forEach(field -> {
                        if (field.isLogicDeleteField()) {
                            tableInfo.getImportPackages().add("com.fasterxml.jackson.annotation.JsonIgnore");
                        }
                    });
                });
    }

    /**
     * 模板配置(TemplateConfig)
     */
    private static BiConsumer<Function<String, String>, TemplateConfig.Builder> templateConfig() {
        return (scanner, builder) -> builder//
                .entity("/templates/entity/entity.java")//
                .service("/templates/service/service.java")//
                .serviceImpl("/templates/service/impl/serviceImpl.java")//
                .mapper("/templates/mapper/mapper.java")//
                .xml(null/*"/templates/mapper/mapper.xml"*/)//
                .controller("/templates/controller/controller.java")//
                // .disable(TemplateType.ENTITY)//
                ;
    }

    /**
     * 模板引擎配置(TemplateEngine)
     */
    private static VelocityTemplateEngine templateEngine() {
        /*
         * 模板引擎配置，默认 Velocity 可选模板引擎 Beetl 或 Freemarker
         * .templateEngine(new BeetlTemplateEngine())
         * .templateEngine(new FreemarkerTemplateEngine())
         */
        return new VelocityTemplateEngine();
    }

    /**
     * 包配置(PackageConfig)
     */
    private static BiConsumer<Function<String, String>, PackageConfig.Builder> packageConfig() {

        return (scanner, builder) -> {
            moduleName = scanner.apply("请输入模块名");
            builder//
                    .parent(parent)//
                    .moduleName(moduleName)//
                    .entity(entity)//
                    .service(service)//
                    .serviceImpl(serviceImpl)//
                    .mapper(mapper)//
                    .xml(xml)//
                    .controller(controller)
            // .pathInfo(Collections.singletonMap(OutputFile.xml, "D://"))//
            ;
        };
    }

    /**
     * 全局配置(GlobalConfig)
     */
    private static BiConsumer<Function<String, String>, GlobalConfig.Builder> globalConfig() {

        return (scanner, builder) -> builder//
                .outputDir(outputDir)//
                .author(author)//
                //.enableSwagger()//
                .dateType(DateType.TIME_PACK)//
                .commentDate("yyyy年MM月dd日 ahh:mm:ss")//
                .enableSpringdoc()//
                // .disableOpenDir()//
                // .enableKotlin()//
                // .disableServiceInterface()//
                ;
    }

    /**
     * 数据库配置(DataSourceConfig)
     */
    private static DataSourceConfig.Builder DataSourceConfig() {

        return new DataSourceConfig//
                .Builder(url, username, password)//
                .typeConvertHandler(typeConvertHandler)//
                // .databaseQueryClass(SQLQuery.class)//
                // .dbQuery(new MySqlQuery())//
                // .schema("mybatis-plus")//
                // .typeConvert(new MySqlTypeConvert())//
                // .keyWordsHandler(new MySqlKeyWordsHandler())//
                // .addConnectionProperty("remarks", "true")//
                ;
    }
}